9.1.1 方法一:重写 onDraw()、dispatchDraw() 函数
一般在自定义 View 时,我们都会重写 onDraw()、dispatchDraw() 函数。先来看一下 onDraw()、dispatchDraw() 函数的定义,如下:
可以看到,onDraw()、dispatchDraw() 函数在传入的参数中都有一个 Canvas 对象。这个 Canvas 对象是 View 中的 Canvas 对象,利用这个 Canvas 对象绘图,效果会直接反映在 View 中。
onDraw()、dispatchDraw() 函数的区别如下:
- onDraw() 函数用于绘制视图自身。
- dispatchDraw() 函数用于绘制子视图。
无论是 View 还是 ViewGroup 对这连个函数的调用顺序都是 onDraw() —> dispatchDraw()。
但在 ViewGroup 中,当它有背景的时候就会调用 onDraw() 函数,否则就会跳过 onDraw() 函数,直接调用 dispatchDraw() 函数。所以,如果要在 ViewGroup 中绘图,往往会重写 dispatchDraw() 函数。
在 View 中,onDraw() 和 dispatchDraw() 函数都会被调用的,所以我们无论把绘图代码放在 onDraw() 函数或者 dispatchDraw() 函数中都是可以得到效果的。但是,由于 dispatchDraw() 函数用于绘制子控件,所以,原则来上讲,在绘制 View 控件时,我们会重写 onDraw() 函数。
总结:在绘制 View 控件时,需要重写 onDraw() 函数;在绘制 ViewGroup 时,需要重写 dispatchDraw() 函数。
9.1.2 方法二:使用 Bitmap 创建
1. 构建方法
使用:
或
其中,bitmap 可以从图片中加载,也可以自行创建。
除这两种方法以外,还有其他几种方法(比如构造一个具有 Matrix 的图像副本),这里不再涉及,大家可以去查看 Bitmap 的构造函数。
2. 在 onDraw() 函数中使用
需要注意的是,如果我们用 Bitmap 构造了一个 Canvas,那这个 Canvas 上绘制的图像也都会保存在这个 Bitmap 上,而不是画在 View 上。如果想画在 View 上就必须使用 OnDraw(Canvas canvas) 函数中传入的 Canvas 画一遍 Bitmap。
下面举个例子:
运行上述代码后会发现,结果是一片空白,我们写的字去哪儿了?在 onDraw() 函数中,我们只是将文字画在了 mBitmapCanvas 上,也就是我们新建 mBitmap 图片上,而最终没有将图片画在画布上。因为文字被写在了图片上,而画布上却没有任何内容,所以结果是一片空白。如果将注释掉的最后一句打开,即可将图片画在画布上,在视图上就会显示文字了,如下图所示。
9.1.3 方法三:调动 SurfaceHolder.lockCanvas() 函数
在使用 SurfaceView 时,当调用 SurfaceHolder.lockCanvas() 函数时,也会创建 Canvas 对象,有关 SurfaceView 的知识可以参考第 10 章。